package com.ktwlrj.core.aspect;

import com.ktwlrj.core.exception.ActionException;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhouxuanhong
 * @date 2019-04-02 16:56
 * @since JDK1.8
 */
@Aspect
@Configuration
public class TranAspect {
    /**
     * 超过2分钟就回滚事物
     */
    private static final int TX_METHOD_TIMEOUT = 120000;

    /**
     * 事物切面
     */
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.ktwlrj.*.service.impl.*.*(..))";

    private final DataSourceTransactionManager transactionManager;

    @Autowired
    public TranAspect(DataSourceTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    @Bean
    public TransactionInterceptor tsAdvice() {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        // 只读事务，不做更新操作
        RuleBasedTransactionAttribute readOnlyTran = new RuleBasedTransactionAttribute();
        readOnlyTran.setReadOnly(true);
        readOnlyTran.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        // 当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务
        RuleBasedTransactionAttribute requiredTran = new RuleBasedTransactionAttribute();
        List<RollbackRuleAttribute> rollbackRuleAttributes = new ArrayList<>();
        // 回滚事物的异常类型
        rollbackRuleAttributes.add(new RollbackRuleAttribute(RuntimeException.class));
        rollbackRuleAttributes.add(new RollbackRuleAttribute(Exception.class));
        rollbackRuleAttributes.add(new RollbackRuleAttribute(ActionException.class));
        rollbackRuleAttributes.add(new RollbackRuleAttribute(NullPointerException.class));
        requiredTran.setRollbackRules(rollbackRuleAttributes);
        requiredTran.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        requiredTran.setTimeout(TX_METHOD_TIMEOUT);
        Map<String, TransactionAttribute> map = new HashMap<>(10);
        // 配置事物操作方式
        map.put("delete*", requiredTran);
        map.put("save*", requiredTran);
        map.put("update*", requiredTran);
        map.put("insert*", requiredTran);
        // select开头的方法,开启只读,提高数据库访问性能
        map.put("select*", readOnlyTran);
        map.put("get*", requiredTran);

        map.put("*", requiredTran);

        source.setNameMap(map);
        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor advisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, tsAdvice());
    }
}
